fix(ios): background widget write is issue-aware and keeps honest metrics; completion write persists the settled tier (#76, #77)#78
Conversation
…rics; completion write persists the settled tier (#76, #77) Ships in the not-yet-archived 1.8.0 (build 33 unchanged, never uploaded). #76: BackgroundSyncService.completeSync persisted "idle"/"error" directly, bypassing the issue-derived tier from #73 - a successful background run (scheduled refresh, overnight catch-up, relay wake-up) overwrote an honest attention snapshot (parked share, disconnected required peer, collision) with a green idle until the next foreground open. The static background context cannot recompute unresolvedIssues (the bridge is already stopped on the background-owned path; peer grace state lives only in the manager), so the foreground now persists an issue floor into the app group on every widget write: max severity of unresolvedIssues plus unreachable folders, excluding the kinds a background run itself invalidates (.staleSync - a successful sync resolves staleness by definition; .backgroundSync - the completion write knows the fresher outcome), so background-only operation cannot stick a false amber. completeSync maps its result to the same severities backgroundSyncIssueItem surfaces in-app, folds the floor in, and derives the tier through SyncHeaderModel.deriveWidgetStatus - one cascade for every status surface (decisions 012/013). An unknown persisted floor decodes as warning, never none. One deliberate visible change: a failed background sync now shows amber "Needs Attention" (the tier the header shows for it on next open) instead of red "Sync Error". Wire compatibility unchanged: fromWire still maps anything unknown to attention, so no combination decodes into a false green. #76 follow-up: the same write also read the folder count and synced-file events only after cleanupBackgroundManaged had stopped the bridge - which then reports an empty folder list, so every background-owned completion rendered "Vaults: 0" on the widget and lost the files count - and stamped its own timestamp as "last sync" for failed runs too. The completion write now runs before cleanup (the values are read while the bridge is still up), a stopped bridge falls back to the previous snapshot's folder count instead of zero, and only a successful run stamps the last-sync triple - a failure carries the previous one forward, so "last synced" keeps naming the last real sync. Assembly is a pure function (fallback matrix fully unit-tested). #77: updateWidgetSyncMetrics derived the completion tier while activeWidgetSyncStart was still non-nil, so completeWidgetSyncSession persisted a stale .syncing snapshot that the poll-end write immediately replaced - two snapshot writes and widget reloads per sync completion. The session is now finalized before the tier is derived; the poll-end write finds an identical snapshot and dedupes to a no-op. No strings added, no Go changes - the earlier-1.8.0 xcframework rebuild note still applies before archiving. Verified: full Xcode test plan green (iPhone 17 Pro simulator, 257/257 incl. the 20 new tests); the two #77 tests were demonstrated red on the unfixed code first, the #76 defects are traced in the Go bridge (stopped engine reports "[]" for folders and events). Fixes #76 Fixes #77
|
Warning Review limit reached
Next review available in: 3 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (6)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Ships in the not-yet-archived 1.8.0 (build 33 unchanged, never uploaded).
#76: BackgroundSyncService.completeSync persisted "idle"/"error" directly,
bypassing the issue-derived tier from #73 - a successful background run
(scheduled refresh, overnight catch-up, relay wake-up) overwrote an honest
attention snapshot (parked share, disconnected required peer, collision)
with a green idle until the next foreground open. The static background
context cannot recompute unresolvedIssues (the bridge is already stopped
on the background-owned path; peer grace state lives only in the manager),
so the foreground now persists an issue floor into the app group on every
widget write: max severity of unresolvedIssues plus unreachable folders,
excluding the kinds a background run itself invalidates (.staleSync - a
successful sync resolves staleness by definition; .backgroundSync - the
completion write knows the fresher outcome), so background-only operation
cannot stick a false amber. completeSync maps its result to the same
severities backgroundSyncIssueItem surfaces in-app, folds the floor in,
and derives the tier through SyncHeaderModel.deriveWidgetStatus - one
cascade for every status surface (decisions 012/013). An unknown persisted
floor decodes as warning, never none. One deliberate visible change: a
failed background sync now shows amber "Needs Attention" (the tier the
header shows for it on next open) instead of red "Sync Error". Wire
compatibility unchanged: fromWire still maps anything unknown to
attention, so no combination decodes into a false green.
#76 follow-up: the same write also read the folder count and synced-file
events only after cleanupBackgroundManaged had stopped the bridge - which
then reports an empty folder list, so every background-owned completion
rendered "Vaults: 0" on the widget and lost the files count - and stamped
its own timestamp as "last sync" for failed runs too. The completion write
now runs before cleanup (the values are read while the bridge is still
up), a stopped bridge falls back to the previous snapshot's folder count
instead of zero, and only a successful run stamps the last-sync triple -
a failure carries the previous one forward, so "last synced" keeps naming
the last real sync. Assembly is a pure function (fallback matrix fully
unit-tested).
#77: updateWidgetSyncMetrics derived the completion tier while
activeWidgetSyncStart was still non-nil, so completeWidgetSyncSession
persisted a stale .syncing snapshot that the poll-end write immediately
replaced - two snapshot writes and widget reloads per sync completion.
The session is now finalized before the tier is derived; the poll-end
write finds an identical snapshot and dedupes to a no-op.
No strings added, no Go changes - the earlier-1.8.0 xcframework rebuild
note still applies before archiving.
Verified: full Xcode test plan green (iPhone 17 Pro simulator, 257/257
incl. the 20 new tests); the two #77 tests were demonstrated red on the
unfixed code first, the #76 defects are traced in the Go bridge (stopped
engine reports "[]" for folders and events).
Fixes #76
Fixes #77